/*
 * @Author: zhang zhijiang 2824735304@qq.com
 * @Date: 2024-12-10 16:32:57
 * @LastEditors: zhang zhijiang 2824735304@qq.com
 * @LastEditTime: 2024-12-10 16:33:02
 * @FilePath: /linux/test_12_10/signal.c
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <semaphore.h>
#include <pthread.h>

#define BUFFER_SIZE 5 // 缓冲区大小

// 定义缓冲区和信号量
int buffer[BUFFER_SIZE];
int in = 0;  // 生产者放置数据的位置
int out = 0; // 消费者取数据的位置
sem_t empty, full, mutex; // 信号量

// 生成者线程
void* producer(void* arg) {
    int item;
    while (1) {
        item = rand() % 100; // 生产一个随机数
        sem_wait(&empty);     // 等待空槽
        sem_wait(&mutex);     // 进入临界区，互斥访问缓冲区

        buffer[in] = item;    // 放入缓冲区
        printf("生产者生产了: %d, 放入位置: %d\n", item, in);
        in = (in + 1) % BUFFER_SIZE; // 循环缓冲区

        sem_post(&mutex);     // 离开临界区
        sem_post(&full);      // 增加一个已填充的槽

        sleep(1); // 模拟生产过程
    }
    return NULL;
}

// 消费者线程
void* consumer(void* arg) {
    int item;
    while (1) {
        sem_wait(&full);      // 等待已填充的槽
        sem_wait(&mutex);     // 进入临界区，互斥访问缓冲区

        item = buffer[out];   // 从缓冲区取出数据
        printf("消费者消费了: %d, 取出位置: %d\n", item, out);
        out = (out + 1) % BUFFER_SIZE; // 循环缓冲区

        sem_post(&mutex);     // 离开临界区
        sem_post(&empty);     // 增加一个空槽

        sleep(1); // 模拟消费过程
    }
    return NULL;
}

int main() {
    pthread_t prod_thread, cons_thread;

    // 初始化信号量
    sem_init(&empty, 0, BUFFER_SIZE); // 初始值为缓冲区大小
    sem_init(&full, 0, 0);            // 初始值为 0，因为开始时没有填充
    sem_init(&mutex, 0, 1);           // 初始值为 1，表示互斥访问缓冲区

    // 创建生成者和消费者线程
    pthread_create(&prod_thread, NULL, producer, NULL);
    pthread_create(&cons_thread, NULL, consumer, NULL);

    // 等待线程结束
    pthread_join(prod_thread, NULL);
    pthread_join(cons_thread, NULL);

    // 销毁信号量
    sem_destroy(&empty);
    sem_destroy(&full);
    sem_destroy(&mutex);

    return 0;
}
